﻿#pragma once

#include <hacks/base/hacks_conf.h>


namespace hacks::net {

    //port for os api : close
    inline int os_sock_close(ev_os_sock_t fd) {
#ifdef  PLATFORM_WIN
        return ::closesocket(fd);
#else
        return ::close(fd);
#endif
    }

    /**
     *
     SHUT_RD   = No more receptions;
     SHUT_WR   = No more transmissions;
     SHUT_RDWR = No more receptions or transmissions.
     */
    inline int os_shutdown(ev_os_sock_t fd, int how) {
#ifdef  PLATFORM_WIN
        static_assert(false,"no windows impl !!!");
        return 0;
#else
        return ::shutdown(fd, how);
#endif
    }


    //port for os api : setsockopt
    inline int os_setsockopt(ev_os_sock_t fd,
                             int level,
                             int option_name,
                             const void *option_value,
                             socklen_t option_len) {
#ifdef PLATFORM_WIN
        return ::setsockopt(fd, level, option_name, static_cast<const char*>(option_value), option_len);
#else
        return ::setsockopt(fd, level, option_name, option_value, option_len);
#endif
    }

    //port for os api : accept and noneblock
    inline ev_os_sock_t os_api_accept(ev_os_sock_t fd) {

        // ReSharper disable once CppJoinDeclarationAndAssignment
        ev_os_sock_t accept_fd;
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
        accept_fd = ::accept4(fd, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
#else
        accept_fd = ::accept(fd, nullptr, nullptr);
#endif

#ifdef PLATFORM_APPLE
        if (accept_fd != INVALID_SOCKET) {
            int no_sig_pipe = 1;
            os_setsockopt(accept_fd, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, sizeof(int));
        }
#endif
        return accept_fd;
    }

    //port for os api : socket
    inline ev_os_sock_t os_sock_new(int domain, int type, int protocol) {
        int flags = 0;
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
        flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
#endif
        ev_os_sock_t new_sock_fd = ::socket(domain, type | flags, protocol);
#ifdef PLATFORM_APPLE
        if (new_sock_fd != INVALID_SOCKET) {
            int no_sig_pipe = 1;
            os_setsockopt(new_sock_fd, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, sizeof(int));
        }
#endif
        return new_sock_fd;
    }

    //port for detected EWOULDBLOCK
    inline bool os_would_block() {
#if defined(PLATFORM_WIN)
        return WSAGetLastError() == WSAEWOULDBLOCK;
#else
        return errno == EWOULDBLOCK;
#endif
    }
}

